#ifdef COMPILE_OPENGL

#include "CBL_Debug.h"
#include "COGL_ShaderProgramAtomic.h"
#include "COGL_GLSLShaderAtomic.h"
#include "CBL_FileSystem.h"
#include "CRL_Main.h"

#include <OpenGL/OpenGL.h>
#include <OpenGL/glext.h>
//#include <cgGL.h>

CB_SUBNAMESPACE_START(OpenGL)

void CShaderProgramAtomic::SetSourceAndCompile(const RenderLib::CShaderProgramDescriptor& _rDescriptor)
{
	if (!Debug::Verify(m_Techniques.Size() == 0, 
					   "Consecutive calls to SetSourceAndCompile() are not allowed.\n"
					   "Use Reload() for shader reloading."))
	{
		return;
	}
	
	m_Descriptor = _rDescriptor;
	
	Reload();
}

// ---------------------------------------------------------------------------------------------------------------------

void CShaderProgramAtomic::Reload()
{
	switch (m_Descriptor.GetLanguage())
	{
		case RenderLib::CShaderProgramDescriptor::OpenGL:
			CompileGLSL();
			break;
			
		case RenderLib::CShaderProgramDescriptor::CG:
			CompileCG();
			break;
			
		default:
			Debug::Error("Chosen shader language not supported bei OpenGL renderer.");
			break;
	}
}

// ---------------------------------------------------------------------------------------------------------------------

void CShaderProgramAtomic::CompileCG()
{
}

// ---------------------------------------------------------------------------------------------------------------------

void CShaderProgramAtomic::CompileGLSL()
{
	typedef RenderLib::CShaderBundleDescriptor::CTechniqueVector::const_iterator CTechniqueIter;
	typedef RenderLib::CShaderBundleTechnique::CPassVector::const_iterator CPassIter;
	
	const RenderLib::CShaderBundleDescriptor& rShaderDescriptor = 
		(const RenderLib::CShaderBundleDescriptor&)m_Descriptor.GetShaderSource(RenderLib::CShaderProgramDescriptor::OpenGL);

	CTechniqueIter TechniqueIter       = rShaderDescriptor.m_Techniques.begin();
	const CTechniqueIter TechniquesEnd = rShaderDescriptor.m_Techniques.end();
	
	while (TechniqueIter != TechniquesEnd)
	{
		CPassIter PassIter        = TechniqueIter->m_Passes.begin();
		const CPassIter PassesEnd = TechniqueIter->m_Passes.end();
		
		while (PassIter != PassesEnd)
		{
			uint32 VtxResource = CompileGLSLPass(PassIter->m_VertexIncludes);
			uint32 FrgResource = CompileGLSLPass(PassIter->m_FragmentIncludes);
			
			const char* pTechniqueName = TechniqueIter->m_Name.c_str();
			const char* pPassName      = PassIter->m_Name.c_str();
			
			RenderLib::CShaderAtomicPtr ExistingPass = GetPass(pTechniqueName, pPassName);
			
			if (ExistingPass.IsValid())
			{
				CGLSLShaderAtomic& rPass = static_cast<CGLSLShaderAtomic&>(*ExistingPass);
				rPass.Reload(VtxResource, FrgResource);
			}
			else
			{
				CGLSLShaderAtomic* pNewPass = new CGLSLShaderAtomic(VtxResource, FrgResource);
				RegisterPass(pNewPass, pTechniqueName, pPassName);
			}
			
			++PassIter;
		}
		
		++TechniqueIter;
	}
}

// ---------------------------------------------------------------------------------------------------------------------

uint32 CShaderProgramAtomic::CompileGLSLPass(const RenderLib::CShaderBundlePass::CStringVector& _rSources)
{
	typedef RenderLib::CShaderBundlePass::CStringVector::const_iterator CSourceIter;
	
	const IFileSystem* pFileSystem = RenderLib::CMain::GetInstance().GetFileSystem();
	
	uint32 NumSources      = _rSources.size();
	char** ppSourceCode    = new char*[NumSources];
	uint32 SourceCodeIndex = 0;
	
	CSourceIter SourceIter       = _rSources.begin();
	const CSourceIter SourcesEnd = _rSources.end();
	
	while (SourceIter != SourcesEnd)
	{
		CFileHandlePtr pSourceHandle = pFileSystem->OpenFile(SourceIter->c_str(), IFileSystem::OpenRead);
		uint32 FileSize = pSourceHandle->GetFileSizeByte();
		
		ppSourceCode[SourceCodeIndex] = new char[FileSize];
		pSourceHandle->Read(ppSourceCode[SourceCodeIndex], FileSize);
		
		++SourceCodeIndex;
		++SourceIter;
	}
	
	uint32 ShaderResource = glCreateShader(GL_VERTEX_SHADER);
			
	CompileGLSLResource(ShaderResource, ppSourceCode, NumSources);
	return ShaderResource;
}

// ---------------------------------------------------------------------------------------------------------------------

void CShaderProgramAtomic::CompileGLSLResource(uint32 _Resource, char** _ppSources, uint32 _NumSources)
{
	int Result = 0;
	
	glShaderSource(_Resource, _NumSources, (const GLchar**)_ppSources, NULL);
	glCompileShader(_Resource); 
	
	glGetShaderiv(_Resource, GL_COMPILE_STATUS, &Result); 
	
	if (Result == 0); 
	{ 
		char ErrorMsg[500]; 
		glGetShaderInfoLog(_Resource, 500, NULL, ErrorMsg); 
		
		Debug::Error("GLSL shader compilation error.\n"
					 "Log says:\n%s", 
					 ErrorMsg);
	} 
}

CB_SUBNAMESPACE_END
#endif